#ifndef SLAB_H
#define SLAB_H 1

/*

	COMM_SLAB is an extension of the communication arbiter

*/
#include "kern_ll.h"
#include "comm_mem.h"
#include <pthread.h>
// when defined, we will use slabs
#define USE_SLAB 1

#define SLAB_PRE_ALLOCATE 1

#define SLAB_PCT 8 // 2%

#define PAGE_SIZE 4096

void init_slab_manager();

#define MAX_SLAB_PCT 80

#define MAX_SLAB_CNT (MAX_SLAB_PCT/SLAB_PCT)

// the threshold is the amt of a request can overlap 
#define SLAB_OVERLAP_THRESHOLD_PCT 60

#define SLAB_SIZE (int)( (float)MEM_SIZE*(float)(SLAB_PCT/100.00)  - ((int)((float)MEM_SIZE*(float)(SLAB_PCT/100.00))%PAGE_SIZE) )

#define SLAB_READ_AHEAD_PCT 10 // 8%


#define SLAB_READ_AHEAD (int)( (float)SLAB_SIZE*(float)(SLAB_READ_AHEAD_PCT/100.00))

//#define SLAB_READ_BEHIND (SLAB_SIZE-SLAB_READ_AHEAD)

// slab will be constant size

void *slab_space;


PLINKEDLIST slab_tables;

// slab table structure
typedef struct
{
	unsigned int fd;
	u_int64_t file_size;
	// should be the domain of the image file
	LINKEDLIST table_list;
	void *slab_table;
	
	void *master_slab // used with pre_allocate_slab
} SLABTABLE, *PSLABTABLE;

typedef struct
{
	// should be the domain of the image file
	u_int64_t offset;
	u_int64_t size_allocated;
	pthread_mutex_t slab_mutex;
	pthread_cond_t slab_signal;
	// reference counter, once zero, can be freed upon timer signal
	int ref_count;
	void *ptr;
} SLAB, *PSLAB;

pthread_condattr_t slab_attr;


// macros which aide the slab
#define GET_SLAB_I(i,s) (PSLAB)(s+(i*sizeof(SLAB)))
#define check(offset,s) (((u_int64_t)((offset/SLAB_SIZE)%MAX_SLAB_CNT)))
#define GET_SLAB_NUM(offset) (((u_int64_t)((offset/SLAB_SIZE)%MAX_SLAB_CNT)))
#define GET_SLAB(offset,s) (PSLAB)(s+(((u_int64_t)((offset/SLAB_SIZE)%MAX_SLAB_CNT))*sizeof(SLAB)))
#define START_OFFSET(offset) ((((u_int64_t)(offset/SLAB_SIZE)))*SLAB_SIZE)
#define SLAB_LOCATION(loc) ( (u_int64_t)(loc/SLAB_SIZE) )
#define WHICH_SLAB(loc) (  SLAB_LOCATION(loc) % MAX_SLAB_CNT )

PSLABTABLE new_slab(unsigned int fd);
PSLABTABLE get_slab(unsigned int fd);
void init_slab_manager();



u_int64_t access_slab(unsigned int fd,char *buf, u_int64_t offset, u_int64_t size);
int queue_slab_and_wait(unsigned int fd, u_int64_t offset, u_int64_t size);
PLINKEDLIST arbitrate_slab_queue(PLINKEDLIST list, unsigned char type);
void free_slab(unsigned int fd, u_int64_t offset);
void release_slab(unsigned int fd, u_int64_t offset);
u_int64_t slab_ptr(unsigned int fd,char **buf, u_int64_t offset, u_int64_t size, char lock);
u_int64_t floating_slab_size;
u_int64_t get_file_size(unsigned int fd);
void decrement_count(unsigned int fd, u_int64_t offset);
short active_slabs;
#endif
